/*
 * Copyright (c) 2013 Yaroslav Stavnichiy <yarosla@gmail.com>
 *
 * This file is part of NXJSON.
 *
 * NXJSON is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation, either version 3
 * of the License, or (at your option) any later version.
 *
 * NXJSON is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with NXJSON. If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef NXJSON_H
#define NXJSON_H

#ifdef  __cplusplus
extern "C" {
#endif

#include <stdint.h>
typedef uint64_t nxjson_u64;
typedef int64_t  nxjson_s64;

typedef enum nx_json_type {
	NX_JSON_NULL,    // this is null value
	NX_JSON_OBJECT,  // this is an object; properties can be found in child nodes
	NX_JSON_ARRAY,   // this is an array; items can be found in child nodes
	NX_JSON_STRING,  // this is a string; value can be found in text_value field
	NX_JSON_INTEGER, // this is an integer; value can be found in int_value field
	NX_JSON_DOUBLE,  // this is a double; value can be found in dbl_value field
	NX_JSON_BOOL     // this is a boolean; value can be found in int_value field
} nx_json_type;

typedef struct nx_json {
	nx_json_type type;     // type of json node, see above
	const char *key;       // key of the property; for object's children only
	struct nx_json *next;  // points to next child

	union {
		const char *text;    // text value of STRING node
    nxjson_u64 u;        // the value of INTEGER or BOOL node
    nxjson_s64 i;
    double     dbl;      // the value of DOUBLE node

    struct {             // children of OBJECT or ARRAY
      int length;
      struct nx_json *first;
      struct nx_json *last;
    } children;
	} val;

} nx_json;

typedef int (*nx_json_unicode_encoder)(unsigned int codepoint, char *p, char **endp);

extern nx_json_unicode_encoder nx_json_unicode_to_utf8;

nx_json *create_json(nx_json_type type, const char *key, nx_json *parent);
const nx_json *nx_json_parse(char *text, nx_json_unicode_encoder encoder);
const nx_json *nx_json_parse_utf8(char *text);
const nx_json *nx_json_get(const nx_json *json, const char *key); // get object's property by key
const nx_json *nx_json_item(const nx_json *json, int idx); // get array element by index
void  nx_json_free(const nx_json *js);

#define NX_JSON_FOREACH_ERRORS(_) \
  _(SUCCESS,                    "Success")                    \
  _(INVALID_UNICODE_ESCAPE,     "Invalid unicode escape")     \
  _(INVALID_UNICODE_SURROGATE,  "Invalid unicode surrogate")  \
  _(INVALID_CODEPOINT,          "Invalid codepoint")          \
  _(MISSING_DOUBLE_EQUOTE,      "Missing double quote")       \
  _(ENDLESS_COMMENT,            "Endless comment")            \
  _(UNEXPECTED_CHARS,           "Unexpected charaters")       \
  _(UNEXPECTED_EOT,             "Unexpected end of text")     \
  _(INVALID_NUMBER,             "Invalid number")

#define NX_JSON_Callback(NAME,_) NX_JSON_ERR_ ## NAME,
enum nx_json_error { NX_JSON_FOREACH_ERRORS(NX_JSON_Callback) };
#undef  NX_JSON_Callback

extern int                NX_JSON_SRC_LINE;
extern enum nx_json_error NX_JSON_ERROR;
extern const char*        NX_JSON_STRING_POS;
extern const char*        NX_JSON_MSGS[NX_JSON_ERR_INVALID_NUMBER + 1];

#ifdef  __cplusplus
}
#endif

#endif  /* NXJSON_H */
